/* Yet Another Experimental Software Renderer
 *
 * Copyright (c) 2010 Pawel "Hery" Dziepak
 */

#include "parser.h"

using namespace yasl;

bool parser::parse(executor *exec) {
	int main = -1;

	while (token->next()) {

		// Read function declaration
		if (!in_function) {
			// Return type
			if (token->get_type() != tokenizer::token_data_type)
				return false;
			func.ret_type = (executor::data_type)tokenizer::find_in(token->get_string().c_str(), tokenizer::data_types, 7);

			// Function name
			if (!token->next() || token->get_type() != tokenizer::token_name)
				return false;
			func.name = get_fname(token->get_string());
			if (token->get_string() == "main")
				main = func.name;

			// (
			if (!token->next() || token->get_type() != tokenizer::token_symbol || token->get_string() != "(")
				return false;

			// Arguments
			do {
				token->next();

				// Argument type
				if (token->get_type() != tokenizer::token_data_type)
					return false;
				executor::decl_var vtemp;
				vtemp.type = (executor::data_type)tokenizer::find_in(token->get_string().c_str(), tokenizer::data_types, 7);

				// Argument name
				if (!token->next() || token->get_type() != tokenizer::token_name)
					return false;
				vtemp.name = get_dname(token->get_string());

				// Add to list
				func.arguments.push_back(vtemp);
			} while (token->next() && token->get_type() == tokenizer::token_symbol && token->get_string() == ",");

			// )
			if (token->get_type() != tokenizer::token_symbol && token->get_string() != ")")
				return false;

			// {
			if (!token->next() && token->get_type() != tokenizer::token_symbol && token->get_string() != "{")
				return false;

			in_function = true;

			continue;
		}

		if (token->get_type() == tokenizer::token_symbol && token->get_string() == "}") {
			exec->define_function(func);
			in_function = false;
			func.arguments.clear();
			func.code.clear();
			d_names.clear();

			continue;
		}

		// Read instructions
		if (token->get_type() == tokenizer::token_keyword) {
			if (token->get_string() == "return") {
				executor::action act;
				act.type = executor::at_return;
				act.ret_to = 0;

				if (!token->next() || token->get_type() != tokenizer::token_name)
					return false;
				executor::var vname;
				vname = expression();
				act.arguments.push_back(vname);

				act_stack.push_back(act);
			}
		}

		if (token->get_type() == tokenizer::token_symbol && token->get_string() == ";") {
			for (int i = 0; i < act_stack.size(); i++)
				func.code.push_back(act_stack[i]);
			act_stack.clear();
		}
	}

	exec->flush(main);
}

executor::var parser::expression() {
	executor::var vfirst;
	if (token->get_type() == tokenizer::token_name) {
		vfirst.ref = true;
		vfirst.value = get_dname(token->get_string());
	} else if (token->get_type() == tokenizer::token_number) {
		vfirst.ref = false;
		vfirst.value = atoi(token->get_string().c_str());
	}

	token->next();
	if (token->get_type() == tokenizer::token_symbol && token->get_string() == ";") {
		return vfirst;
	}

	if (token->get_type() == tokenizer::token_operator) {
		// Set action type
		executor::action act;
		act.type = executor::at_operator;

		executor::var vname;

		// Pass operator
		vname.value = tokenizer::find_in(token->get_string().c_str(), tokenizer::operators, 7);
		vname.ref = false;
		act.arguments.push_back(vname);

		// Pass first argument
		act.arguments.push_back(vfirst);

		// Pass second argument
		token->next();
		vname = expression();
		act.arguments.push_back(vname);

		// Ret to
		act.ret_to = new_dname();
		
		act_stack.push_back(act);
		executor::var vret = {act.ret_to, true};
		return vret;
	}

}

/*
 Grammar

 Function definition:
 data_type name(data_type name...) {
	...
 }

 Return instruction:
	return ...;
*/